/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "imageknife_napi.h"
#include "imageknife_internal.h"
#include "imageknife.h"
#include "imageknife_node_animator.h"
#include "imageknife_node_image.h"
#include "imageknife_request.h"
#include "option/animator_option_napi.h"
#include "option/imageknife_option_napi.h"
#include "promise/promise_napi.h"
#include "utils/napi_parser.h"
#include "imageknife_node_custom.h"
#include "utils/imageknife_trace.h"

namespace ImageKnifePro {

void ImageKnifeNapi::ParseComponentAttribute(napi_env env, napi_value object, std::shared_ptr<ImageKnifeNode> imageNode)
{
    IMAGE_KNIFE_CHECK(imageNode == nullptr);
    napi_value propertyValue = NapiParser::ParseProperty(env, object, "syncLoad");
    if (propertyValue != nullptr) {
        imageNode->SyncLoad(NapiParser::ParseBoolean(env, propertyValue, false));
    }

    propertyValue = NapiParser::ParseProperty(env, object, "draggable");
    if (propertyValue != nullptr) {
        imageNode->Draggable(NapiParser::ParseBoolean(env, propertyValue, false));
    }

    propertyValue = NapiParser::ParseProperty(env, object, "adaptable");
    if (propertyValue != nullptr) {
        imageNode->Adaptable(NapiParser::ParseBoolean(env, propertyValue, false));
    }
}

// static
napi_value ImageKnifeNapi::CreateNativeRoot(napi_env env, napi_callback_info info)
{
    const size_t argSize = 6;
    const size_t optionIndex = 2;
    const size_t animatorOptionIndex = 3;
    const size_t contextIndex = 4;
    const size_t componentAttrIndex = 5;

    size_t argc = argSize;
    napi_value args[argSize] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取NodeContent
    ArkUI_NodeContentHandle contentHandle;
    OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[1], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[1], componentId, length + 1, nullptr);
    ImageKnifeTrace trace("Napi CreateNativeRoot", componentId);
    trace.StartSyncTrace();

    // 获取ImageKnifeOption
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[optionIndex]);

    // 获取AnimatorOption
    auto animatorOption = std::make_shared<AnimatorOptionNapi>(env, args[animatorOptionIndex]);

    // 设置和覆盖context
    imageKnifeOption->ParseContext(env, args[contextIndex]);

    auto imageKnifeNode = std::make_shared<ImageKnifeNodeImage>(imageKnifeOption);
    imageKnifeNode->UpdateAnimatorOption(animatorOption);
    ParseComponentAttribute(env, args[componentAttrIndex], imageKnifeNode);

    imageKnifeNode->SetComponentId(std::string(componentId));
    // 设置contentHandle, 挂载imageNode, 保持Native侧对象到管理类中，维护生命周期。
    ImageKnifeInternal::GetInstance().SetRootNode(componentId, contentHandle, imageKnifeNode);
    imageKnifeNode->Execute();
    return nullptr;
}

napi_value ImageKnifeNapi::UpdateNativeRoot(napi_env env, napi_callback_info info)
{
    const size_t argSize = 4;
    const size_t contextIndex = 3;
    const size_t syncLoadIndex = 2;
    size_t argc = argSize;
    napi_value args[argSize] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[0], componentId, length + 1, nullptr);
    ImageKnifeTrace trace("Napi UpdateNativeRoot", componentId);
    trace.StartSyncTrace();

    // 获取imageKnifeOption
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[1]);

    // 获取syncLoad
    bool syncLoad = false;
    napi_get_value_bool(env, args[syncLoadIndex], &syncLoad);

    // 设置和覆盖context
    imageKnifeOption->ParseContext(env, args[contextIndex]);

    // 找到ImageNode
    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        // 通过imageKnifeOption 更新请求
        imageNode->Update(imageKnifeOption);
        // request 更新完成后，更新request的 syncLoad状态
        imageNode->SyncLoad(syncLoad);
    }

    return nullptr;
}

napi_value ImageKnifeNapi::UpdateNodeDraggable(napi_env env, napi_callback_info info)
{
    const size_t argSize = 2;
    size_t argc = argSize;
    napi_value args[argSize] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    std::string componentId = NapiParser::ParseString(env, args[0]);
    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        bool draggable = false;
        napi_get_value_bool(env, args[1], &draggable);
        imageNode->Draggable(draggable);
    }
    return nullptr;
}

napi_value ImageKnifeNapi::ClearNativeRoot(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[0], componentId, length + 1, &length);
    ImageKnifeTrace trace("Napi ClearNativeRoot", componentId);
    trace.StartSyncTrace();

    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        imageNode->Clear();
        ImageKnife::GetInstance().CancelRequest(imageNode->GetImageKnifeRequest());
    }
    return nullptr;
}

napi_value ImageKnifeNapi::DestroyNativeRoot(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value arg;
    napi_get_cb_info(env, info, &argc, &arg, nullptr, nullptr);

    size_t length;
    napi_get_value_string_utf8(env, arg, nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, arg, componentId, length + 1, &length);
    ImageKnifeTrace trace("Napi DestroyNativeRoot", componentId);
    trace.StartSyncTrace();

    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        imageNode->DisposeNode();
    }

    return nullptr;
}

napi_value ImageKnifeNapi::UpdateNodeAdaptable(napi_env env, napi_callback_info info)
{
    const size_t argSize = 2;
    size_t argc = argSize;
    napi_value args[argSize] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string componentId = NapiParser::ParseString(env, args[0]);

    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        bool adaptable = false;
        napi_get_value_bool(env, args[1], &adaptable);
        imageNode->Adaptable(adaptable);
    }
    return nullptr;
}

napi_value ImageKnifeNapi::CreateNativeImageView(napi_env env, napi_callback_info info)
{
    const size_t argSize = 6;
    const size_t optionIndex = 2;
    const size_t contextIndex = 3;
    const size_t animatorOptionIndex = 4;
    const size_t componentAttrIndex = 5;
    size_t argc = argSize;
    napi_value args[argSize] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取NodeContent
    ArkUI_NodeContentHandle contentHandle;
    OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);

    // 获取componentId
    std::string componentId = NapiParser::ParseString(env, args[1]);
    ImageKnifeTrace trace("Napi CreateNativeImageView", componentId);
    trace.StartSyncTrace();

    // 获取ImageKnifeOption
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[optionIndex]);

    // 获取AnimatorOption
    auto animatorOption = std::make_shared<AnimatorOptionNapi>(env, args[animatorOptionIndex]);
    // 设置和覆盖context
    imageKnifeOption->ParseContext(env, args[contextIndex]);

    auto imageNode = ImageKnifeNode::CreateImageKnifeView(componentId, contentHandle, imageKnifeOption, animatorOption);
    ParseComponentAttribute(env, args[componentAttrIndex], imageNode);

    imageNode->Execute();
    return nullptr;
}

napi_value ImageKnifeNapi::PreCreateNativeNode(napi_env env, napi_callback_info info)
{
    const size_t argSize = 2;
    size_t argc = argSize;
    napi_value args[argSize] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取componentId
    std::string customId = NapiParser::ParseString(env, args[0]);
    ImageKnifeTrace trace("Napi PreCreateNativeNode", customId);
    trace.StartSyncTrace();
    // 获取ImageKnifeOption
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[1]);
    auto imageNode = std::make_shared<ImageKnifeNodeImage>(imageKnifeOption);
    imageNode->SetComponentId(customId);
    ImageKnifeInternal::GetInstance().SetPreCreatedNode(customId, imageNode);

    // 直接Execute 预创建组件，不上树 不关联
    ImageKnifeInternal::GetInstance().Execute(imageNode->GetImageKnifeRequest());
    return nullptr;
}

napi_value ImageKnifeNapi::ConnectContentSlot(napi_env env, napi_callback_info info)
{
    const size_t argSize = 7;
    const size_t contentSlotIndex = 2;
    const size_t imageKnifeOptionIndex = 3;
    const size_t animatorOptionIndex = 4;
    const size_t contextIndex = 5;
    const size_t componentAttrIndex = 6;
    size_t argc = argSize;
    napi_value args[argSize] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    std::string componentId = NapiParser::ParseString(env, args[0]);
    std::string customId = NapiParser::ParseString(env, args[1]);

    ImageKnifeTrace trace("Napi ConnectContentSlot customId:" + customId, componentId);
    trace.StartSyncTrace();
    auto imageNode = ImageKnifeInternal::GetInstance().GetPreCreatedNode(customId, true);

    // 获取NodeContent
    ArkUI_NodeContentHandle contentHandle;
    OH_ArkUI_GetNodeContentFromNapiValue(env, args[contentSlotIndex], &contentHandle);

    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[imageKnifeOptionIndex]);
    imageKnifeOption->ParseContext(env, args[contextIndex]);
    bool exist = true;
    if (imageNode == nullptr) {
        exist = false;
        // 如果componentId 未找到, 则创建该组件
        IMAGE_KNIFE_LOG(LOG_WARN, "[ID:%{public}s]  Not Found PreCreated Node, Create It", componentId.c_str());
        imageNode = std::make_shared<ImageKnifeNodeImage>(imageKnifeOption);
    } else {
        IMAGE_KNIFE_LOG(LOG_DEBUG, "[ID:%{public}s]  Pre Created Node Connect ContentSlot", componentId.c_str());
    }

    imageNode->SetComponentId(componentId);
    // 获取AnimatorOption
    auto animatorOption = std::make_shared<AnimatorOptionNapi>(env, args[animatorOptionIndex]);
    imageNode->UpdateAnimatorOption(animatorOption);

    ParseComponentAttribute(env, args[componentAttrIndex], imageNode);
    // 重新设置关联
    ImageKnifeInternal::GetInstance().SetRootNode(componentId, contentHandle, imageNode);

    // 未上树，进行上树显示
    imageNode->Execute();
    if (exist) {
        // 需要更新id设置imageNode以后再发起
        imageNode->Update(imageKnifeOption);
    }
    return nullptr;
}

napi_value ImageKnifeNapi::SetMaxPreCreateNodeCount(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value value;
    napi_get_cb_info(env, info, &argc, &value, nullptr, nullptr);
    ImageKnifeInternal::GetInstance().SetMaxPreCreateNodeCount(NapiParser::ParseUint32(env, value));
    return nullptr;
}

napi_value ImageKnifeNapi::ReleasePreCreatedNode(napi_env env, napi_callback_info info)
{
    ImageKnifeInternal::GetInstance().ReleasePreCreatedNode();
    return nullptr;
}

napi_value ImageKnifeNapi::FileCacheEnableExtension(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value value;
    napi_get_cb_info(env, info, &argc, &value, nullptr, nullptr);
    ImageKnife::GetInstance().FileCacheEnableExtension(NapiParser::ParseString(env, value));
    return nullptr;
}

napi_value ImageKnifeNapi::InitFileCache(napi_env env, napi_callback_info info)
{
    napi_status status;
    const size_t argCount = 4;
    const size_t maxLength = 512;
    const int memorySizeArgIndex = 2;
    const int pathArgIndex = 3;

    auto promise = std::make_shared<PromiseNapi<void>>();
    // 获取传递的参数
    size_t argc = argCount;
    napi_value args[argCount];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取 filesDir 参数
    size_t strLength = 0;
    char jsFileDir[maxLength + 1] = {0};
    status = napi_get_value_string_utf8(env, args[0], jsFileDir, maxLength, &strLength);
    if (status != napi_ok || strLength > maxLength || strLength < 0) {
        return promise->Reject("Parse file dir error");
    }
    std::string fileDir(jsFileDir);

    // 获取 size 参数
    int32_t fileSize = 0;
    napi_get_value_int32(env, args[1], &fileSize);

    // 获取 memory 参数
    int32_t memorySize = 0;
    napi_get_value_int32(env, args[memorySizeArgIndex], &memorySize);

    // 获取 path 参数
    char jsPath[maxLength] = {0};
    napi_get_value_string_utf8(env, args[pathArgIndex], jsPath, maxLength, nullptr);
    std::string path(jsPath);

    auto initFunc = [fileDir, fileSize, memorySize, path](void* data) {
        ImageKnifeInternal::GetInstance().InitFileCache(fileDir, fileSize, memorySize, path);
    };

    bool res = TaskWorker::GetInstance()->PushTask(initFunc, [promise](void*) {promise->Resolve();},
                                                   nullptr, "InitFileCache");
    if (res) {
        return promise->GetPromise();
    }
    return promise->Reject("Push Thread Failed");
}

napi_value ImageKnifeNapi::GetCacheImage(napi_env env, napi_callback_info info)
{
    const size_t argCount = 4;
    const size_t signatureIndex = 2;
    const size_t animatorIndex = 3;
    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[0]);
    CacheStrategy cacheType = NapiParser::ParseCacheStrategy(env, args[1]);
    std::string signature = NapiParser::ParseString(env, args[signatureIndex]);
    bool animator = false;
    napi_get_value_bool(env, args[animatorIndex], &animator);

    auto promise = std::make_shared<PromiseNapi<std::shared_ptr<ImageData>>>();
    ImageKnifeInternal::GetInstance().GetCacheImage(promise, imageKnifeOption, cacheType, signature, animator);
    return promise->GetPromise();
}

napi_value ImageKnifeNapi::Preload(napi_env env, napi_callback_info info)
{
    napi_status status;
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取传入的 request 参数
    napi_value jsRequest = args[0];

    // 从 request 中获取 imageKnifeOption 属性
    napi_value jsImageKnifeOption;
    status = napi_get_named_property(env, jsRequest, "imageKnifeOption", &jsImageKnifeOption);
    if (status != napi_ok) {
        napi_throw_error(env, "IMAGE_KNIFE_C", "Failed to get 'imageKnifeOption' property from request");
        return nullptr;
    }

    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, jsImageKnifeOption);

    std::shared_ptr<ImageKnifeRequestInternal> request =
        std::dynamic_pointer_cast<ImageKnifeRequestInternal>(ImageKnife::GetInstance().Preload(imageKnifeOption));
    if (!request) {
        napi_throw_error(env, "IMAGE_KNIFE_C", "Failed to cast request");
        return nullptr;
    }

    request->SetEnv(env);

    // 创建对 jsRequest 的引用并保存到 request 中
    napi_ref jsRequestRef = nullptr;

    // 第四个参数必填项，即使不使用
    status = napi_wrap(env, args[0], request.get(), [](napi_env env, void* data, void* hint) {},
                       nullptr, &jsRequestRef);
    if (status != napi_ok) {
        IMAGE_KNIFE_LOG(LOG_ERROR, "Failed to bind the JavaScript object");
    }

    request->SetJsRequestRef(jsRequestRef);
    return jsRequest;
}

napi_value ImageKnifeNapi::PreloadCache(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[0]);
    auto promise = std::make_shared<PromiseNapi<std::string>>();
    
    auto request = std::make_shared<ImageKnifeRequestInternal>(imageKnifeOption, promise);
    ImageKnifeInternal::GetInstance().Execute(request);
    return promise->GetPromise();
}

napi_value ImageKnifeNapi::Cancel(napi_env env, napi_callback_info info)
{
    napi_status status;
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    if (status != napi_ok) {
        return nullptr;
    }

    ImageKnifeRequestInternal* request = nullptr;
    status = napi_unwrap(env, args[0], (void**)&request);
    if (status != napi_ok) {
        IMAGE_KNIFE_LOG(LOG_ERROR, "Failed to unwrap");
        return nullptr;
    }

    if (request == nullptr) {
        // Native 侧request已加载完毕并析构
        return nullptr;
    }

    // 恢复成智能指针
    auto requestSharePtr = request->shared_from_this();
    ImageKnife::GetInstance().CancelRequest(requestSharePtr);
    return nullptr;
}

napi_value ImageKnifeNapi::Reload(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    std::string requestId;
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    size_t length;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &length);
    requestId.resize(length);
    napi_get_value_string_utf8(env, args[0], &requestId[0], length + 1, nullptr);

    ImageKnife::GetInstance().Reload(requestId);
    return nullptr;
}

napi_value ImageKnifeNapi::SetMaxRequests(napi_env env, napi_callback_info info)
{
    // 获取传递的参数数量
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    napi_value jsConcurrency = args[0];
    int concurrency = 8;
    napi_get_value_int32(env, jsConcurrency, &concurrency);

    ImageKnife::GetInstance().SetMaxRequests(concurrency);
    return nullptr;
}

napi_value ImageKnifeNapi::CreateAnimatorImage(napi_env env, napi_callback_info info)
{
    size_t argc = 5;
    const size_t imageKnifeOptionIndex = 2;
    const size_t animatorOptionIndex = 3;
    const size_t contextIndex = 4;
    napi_value args[5] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取NodeContent
    ArkUI_NodeContentHandle contentHandle;
    OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[1], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[1], componentId, length + 1, nullptr);
    ImageKnifeTrace trace("Napi CreateAnimatorImage", componentId);
    trace.StartSyncTrace();

    // 获取ImageKnifeOption
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[imageKnifeOptionIndex]);
    // 设置context
    imageKnifeOption->ParseContext(env, args[contextIndex]);
    // 获取AnimatorOption
    auto animatorOption = std::make_shared<AnimatorOptionNapi>(env, args[animatorOptionIndex]);

    // 创建ImageKnifeNodeAnimator, 并挂载上树
    auto imageKnifeNodeAnimator = std::make_shared<ImageKnifeNodeAnimator>(imageKnifeOption, animatorOption);
    imageKnifeNodeAnimator->SetComponentId(std::string(componentId));

    ImageKnifeInternal::GetInstance().SetRootNode(componentId, contentHandle, imageKnifeNodeAnimator);
    imageKnifeNodeAnimator->Execute();
    return nullptr;
}

napi_value ImageKnifeNapi::UpdateAnimatorImage(napi_env env, napi_callback_info info)
{
    size_t argc = 4;
    const size_t animatorOptionIndex = 2;
    const size_t contextIndex = 3;
    napi_value args[5] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[0], componentId, length + 1, nullptr);

    // 获取ImageKnifeOption
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[1]);
    // 设置context
    imageKnifeOption->ParseContext(env, args[contextIndex]);

    // 获取AnimatorOption
    auto animatorOption = std::make_shared<AnimatorOptionNapi>(env, args[animatorOptionIndex]);

    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        imageNode->UpdateAnimatorOption(animatorOption);
        // 通过imageKnifeOption 更新请求
        imageNode->Update(imageKnifeOption);
    }
    return nullptr;
}

napi_value ImageKnifeNapi::ControlAnimatorImage(napi_env env, napi_callback_info info)
{
    size_t argc = 3;
    const size_t animatorOptionIndex = 1;
    napi_value args[3] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[0], componentId, length + 1, nullptr);

    // 获取AnimatorOption
    auto animatorOption = std::make_shared<AnimatorOptionNapi>(env, args[animatorOptionIndex]);

    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        imageNode->UpdateAnimatorOption(animatorOption);
    }
    return nullptr;
}

napi_value ImageKnifeNapi::ClearAnimatorImage(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[0], componentId, length + 1, nullptr);

    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        imageNode->Clear();
        ImageKnife::GetInstance().CancelRequest(imageNode->GetImageKnifeRequest());
    }
    return nullptr;
}

napi_value ImageKnifeNapi::DestroyAnimatorImage(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 获取componentId
    size_t length;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &length);
    char componentId[length + 1];
    napi_get_value_string_utf8(env, args[0], componentId, length + 1, nullptr);

    auto imageNode =  ImageKnifeInternal::GetInstance().GetImageNode(componentId);
    if (imageNode != nullptr) {
        imageNode->DisposeNode();
    }
    return nullptr;
}

napi_value ImageKnifeNapi::AddSmallEndFileCache(napi_env env, napi_callback_info info)
{
    const size_t argCount = 5;
    const size_t filePathIndex = 2;
    const size_t maxSizeIndex = 3;
    const size_t maxDiskUsage = 4;
    size_t argc = argCount;

    napi_value args[argCount];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    std::string cacheName = NapiParser::ParseString(env, args[0]);
    std::string sandbox = NapiParser::ParseString(env, args[1]);
    std::string filePath = NapiParser::ParseString(env, args[filePathIndex]);
    size_t maxSize = NapiParser::ParseUint32(env, args[maxSizeIndex]);
    size_t maxUsage = NapiParser::ParseUint32(env, args[maxDiskUsage]);

    auto promise = std::make_shared<PromiseNapi<int>>();
    CacheErrorCode errorCode = ImageKnife::GetInstance().AddSmallEndFileCache(cacheName, sandbox, filePath);
    if (errorCode != CacheErrorCode::SUCCESS) {
        promise->Resolve(static_cast<int>(errorCode));
        return promise->GetPromise();
    }

    TaskWorker::GetInstance()->PushTask([cacheName, maxSize, maxUsage](void *) {
        ImageKnifeInternal::GetInstance().InitSmallEndFileCacheSync(cacheName, maxSize, maxUsage);
        }, [promise](void *) {promise->Resolve(static_cast<int>(CacheErrorCode::SUCCESS));}, nullptr);

    return promise->GetPromise();
}

napi_value ImageKnifeNapi::IsFileCacheInit(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value value;
    napi_get_cb_info(env, info, &argc, &value, nullptr, nullptr);

    napi_value result;
    napi_get_boolean(env, ImageKnife::GetInstance().IsFileCacheInit(NapiParser::ParseString(env, value)), &result);
    return result;
}

napi_value ImageKnifeNapi::GetCacheLimitNum(napi_env env, napi_callback_info info)
{
    const size_t argCount = 2;
    size_t argc = argCount;
    napi_value args[argCount];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    CacheStrategy strategy = static_cast<CacheStrategy>(NapiParser::ParseInt(env, args[0]));
    std::string cacheName = NapiParser::ParseString(env, args[1]);

    napi_value result;
    napi_create_int64(env, ImageKnife::GetInstance().GetCacheLimitNum(strategy, cacheName), &result);
    return result;
}

napi_value ImageKnifeNapi::GetCacheLimitSize(napi_env env, napi_callback_info info)
{
    const size_t argCount = 2;
    size_t argc = argCount;
    napi_value args[argCount];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    CacheStrategy strategy = static_cast<CacheStrategy>(NapiParser::ParseInt(env, args[0]));
    std::string cacheName = NapiParser::ParseString(env, args[1]);

    napi_value result;
    napi_create_int64(env, ImageKnife::GetInstance().GetCacheLimitSize(strategy, cacheName), &result);

    return result;
}

napi_value ImageKnifeNapi::GetCurrentCacheNum(napi_env env, napi_callback_info info)
{
    const size_t argCount = 2;
    size_t argc = argCount;
    napi_value args[argCount];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    CacheStrategy strategy = static_cast<CacheStrategy>(NapiParser::ParseInt(env, args[0]));
    std::string cacheName = NapiParser::ParseString(env, args[1]);

    napi_value result;
    napi_create_int64(env, ImageKnife::GetInstance().GetCurrentCacheNum(strategy, cacheName), &result);

    return result;
}

napi_value ImageKnifeNapi::GetCurrentCacheSize(napi_env env, napi_callback_info info)
{
    const size_t argCount = 2;
    size_t argc = argCount;
    napi_value args[argCount];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    CacheStrategy strategy = static_cast<CacheStrategy>(NapiParser::ParseInt(env, args[0]));
    std::string cacheName = NapiParser::ParseString(env, args[1]);

    napi_value result;
    napi_create_int64(env, ImageKnife::GetInstance().GetCurrentCacheSize(strategy, cacheName), &result);

    return result;
}

napi_value ImageKnifeNapi::AddHeader(napi_env env, napi_callback_info info)
{
    const size_t argsLength = 2;
    const size_t maxKeyLength = 128;
    const size_t maxValueLength = 256;
    napi_value argv[argsLength];
    size_t args = argsLength;
    napi_get_cb_info(env, info, &args, argv, nullptr, nullptr);

    char key[maxKeyLength] = {0};
    size_t keyLength = 0;
    napi_get_value_string_utf8(env, argv[0], key, maxKeyLength, &keyLength);
    key[keyLength] = 0;

    char value[maxValueLength] = {0};
    size_t valueLength = 0;
    napi_get_value_string_utf8(env, argv[1], value, maxValueLength, &valueLength);
    value[valueLength] = 0;

    ImageKnife::GetInstance().AddHeader(std::string(key), std::string(value));

    return nullptr;
}

napi_value ImageKnifeNapi::DeleteHeader(napi_env env, napi_callback_info info)
{
    const size_t maxKeyLength = 128;
    napi_value jsKey;
    size_t args = 1;
    napi_get_cb_info(env, info, &args, &jsKey, nullptr, nullptr);

    char key[maxKeyLength] = {0};
    size_t keyLength = 0;
    napi_get_value_string_utf8(env, jsKey, key, maxKeyLength, &keyLength);
    key[keyLength] = 0;

    ImageKnife::GetInstance().DeleteHeader(std::string(key));
    return nullptr;
}

napi_value ImageKnifeNapi::RemoveAllMemoryCache(napi_env env, napi_callback_info info)
{
    ImageKnife::GetInstance().RemoveAllMemoryCache();
    return nullptr;
}

napi_value ImageKnifeNapi::RemoveMemoryCache(napi_env env, napi_callback_info info)
{
    napi_status status;
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    napi_value jsImageKnifeOption = args[0];
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, jsImageKnifeOption);
    ImageKnife::GetInstance().RemoveMemoryCache(imageKnifeOption);
    return nullptr;
}

napi_value ImageKnifeNapi::RemoveAllFileCache(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value value;
    napi_get_cb_info(env, info, &argc, &value, nullptr, nullptr);
    std::string cacheName = NapiParser::ParseString(env, value);
    AsyncFunc asyncFunc = [cacheName](void *data) {
        ImageKnifeInternal::GetInstance().RemoveAllFileCache(cacheName);
    };

    auto promise = std::make_shared<PromiseNapi<void>>();
    bool res = TaskWorker::GetInstance()->PushTask(asyncFunc, [promise](void*) {promise->Resolve();},
                                                   nullptr, "RemoveAllFileCache");
    if (res) {
        return promise->GetPromise();
    }
    return promise->Reject("Push Thread Failed");
}

napi_value ImageKnifeNapi::RemoveFileCache(napi_env env, napi_callback_info info)
{
    napi_value jsImageKnifeOption;
    size_t args = 1;
    napi_get_cb_info(env, info, &args, &jsImageKnifeOption, nullptr, nullptr);
    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, jsImageKnifeOption);

    ImageKnifeInternal::GetInstance().RemoveFileCache(imageKnifeOption);
    return nullptr;
}

napi_value ImageKnifeNapi::SetCacheLimit(napi_env env, napi_callback_info info)
{
    const size_t argLength = 4;
    const size_t maxUsageIndex = 2;
    const size_t cacheNameIndex = 3;

    size_t argc = argLength;
    napi_value args[argLength];

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    int32_t strategy = 0;
    int32_t maxSize = 0;
    int32_t maxUsage = 0;
    
    napi_get_value_int32(env, args[0], &strategy);
    napi_get_value_int32(env, args[1], &maxSize);
    napi_get_value_int32(env, args[maxUsageIndex], &maxUsage);

    std::string cacheName = NapiParser::ParseString(env, args[cacheNameIndex]);

    ImageKnife::GetInstance().SetCacheLimit(static_cast<CacheStrategy>(strategy), maxSize, maxUsage, cacheName);
    return nullptr;
}

napi_value ImageKnifeNapi::PutCacheImage(napi_env env, napi_callback_info info)
{
    const size_t argCount = 5;
    const size_t cacheTypeIndex = 2;
    const size_t signatureIndex = 3;
    const size_t cacheNameIndex = 4;

    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    std::string url = NapiParser::ParseString(env, args[0]);

    OH_PixelmapNative *pixelmap = nullptr;
    if (OH_PixelmapNative_ConvertPixelmapNativeFromNapi(env, args[1], &pixelmap) != IMAGE_SUCCESS) {
        IMAGE_KNIFE_LOG(LOG_ERROR, "Convert Pixelmap from Napi Failed");
        return nullptr;
    }
    auto imageData = std::make_shared<ImageData>(pixelmap);

    int cacheStrategy = 0;
    napi_get_value_int32(env, args[cacheTypeIndex], &cacheStrategy);

    std::string signature = NapiParser::ParseString(env, args[signatureIndex]);
    std::string cacheName = NapiParser::ParseString(env, args[cacheNameIndex]);

    ImageKnife::GetInstance().PutCacheImage(url, imageData, static_cast<CacheStrategy>(cacheStrategy),
                                            signature, cacheName);
    return nullptr;
}

} // end of namespace
